package cn.lijiajia3515.cairo.auth.framework.security.web.authentication.captcha;

import lombok.Setter;
import org.springframework.core.log.LogMessage;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.time.Instant;
import java.util.Optional;

/**
 * 校验码 过滤器
 */
public class CaptchaVerifyFilter extends AbstractCaptchaFilter {
	public static final String VERIFY_CODE_PARAMETER_NAME = "verify_code";

	/**
	 * 请求数据
	 */
	@Setter
	public String verifyCodeParameterName;

	public CaptchaVerifyFilter(RequestMatcher requestMatcher) {
		super(requestMatcher);
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
		if (requires(request, response)) {
			HttpSession session = request.getSession(true);
			Instant expire = Optional.ofNullable(session.getAttribute(getVerifyCodeExpireAttributeName()))
				.map(x -> Instant.ofEpochMilli(Long.parseLong(x.toString()))).orElse(null);

			if (expire != null && Instant.now().isAfter(expire)) {
				session.removeAttribute(getVerifyCodeAttributeName());
				session.removeAttribute(getVerifyCodeExpireAttributeName());
				throw new CaptchaVerifyException("校验码已过期", VerifyBusiness.Expire);
			}
			Object sessionCaptchaCode = session.getAttribute(getVerifyCodeAttributeName());
			Optional.ofNullable(sessionCaptchaCode)
				.ifPresentOrElse(code -> {
						String parameterVerifyCode = request.getParameter(getVerifyCodeParameterName());
						if (!code.toString().equalsIgnoreCase(parameterVerifyCode))
							throw new CaptchaVerifyException("校验码错误", VerifyBusiness.Bad);

						session.removeAttribute(getVerifyCodeAttributeName());
						session.removeAttribute(getVerifyCodeExpireAttributeName());
						if (this.logger.isTraceEnabled()) {
							this.logger.trace(LogMessage.format("captcha verify success %s", requestMatcher));
						}
					},
					() -> {
						throw new CaptchaVerifyException("未进行人机验证", VerifyBusiness.NotExist);
					});
		}
		filterChain.doFilter(request, response);
	}

	public String getVerifyCodeParameterName() {
		return Optional.ofNullable(this.verifyCodeParameterName).orElse(VERIFY_CODE_PARAMETER_NAME);
	}
}
